package com.mm.exception;

import com.mm.plugin.logging.enums.ResultCodeEnum;
import com.mm.utils.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 统一异常处理
 */
@RestControllerAdvice
@Slf4j
public class GlobalException {

    //从配置文件中获取登录的邮箱账号作为发送者邮箱
    /*@Value("${spring.mail.username}")
    private String FromEmail;*/

   /* @Autowired
    JavaMailSender javaMailSender;
*/
    //环境
   /* @Value("${surroundings}")
    private String surroundings;*/


    /**
     * 未定义异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler({Exception.class})
    public ApiResult handleIndexOutOfBoundsException(Exception e, HttpServletRequest request) {
        e.printStackTrace();
        log.error(e.toString());
        //发送邮件
        String servletPath = request.getServletPath();
       /* if ("dev".equals(surroundings)){
            return ApiResult.fail(ResultCodeEnum.SERVER_BUSY);
        }*/
//        sendEmail(e,surroundings,servletPath);
        return ApiResult.fail(ResultCodeEnum.SERVER_BUSY);
    }

    /*private void sendEmail(Exception e, String surroundings,String servletPath) {
        e.printStackTrace();
        String[] a = new String[]{"wangdx@prust.cn", "taocheng@prust.cn"};
        Email email = new Email();
        email.setTitle("眼视光系统异常通知-" + surroundings + "环境");
        email.setContext("异常的方法路径：" + servletPath + "\n控制器:" + e.getStackTrace()[0].getClassName() + "\n第" + e.getStackTrace()[0].getLineNumber() + "行\n" + "[" + e.getStackTrace()[0].getMethodName() + "]" + "方法出现异常:\n" + e.toString());
        email.setEmail("wangdx@prust.cn");
        SimpleMailMessage message = new SimpleMailMessage(); //创建一封邮件
        message.setFrom(FromEmail); //发送者邮箱
        message.setTo(a); //接收者邮箱
        message.setSubject(email.getTitle()); //邮件的标题
        message.setText(email.getContext()); //邮件内容
        javaMailSender.send(message); //发送
    }*/

    /**
     * 参数类型不匹配
     */
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiResult requestTypeMismatch(MethodArgumentTypeMismatchException e) {
        e.printStackTrace();
        log.error(e.getMessage());
        return ApiResult.fail(ResultCodeEnum.BODY_NOT_MATCH.getCode(), "参数类型不匹配，参数" + e.getName() + "类型必须为" + e.getRequiredType());
    }


    /**
     * JSON方式参数校验
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ApiResult methodDtoNotValidException(Exception ex, HttpServletRequest request) {
        ex.printStackTrace();
        log.error(ex.getMessage());
        MethodArgumentNotValidException c = (MethodArgumentNotValidException) ex;
        List<ObjectError> errors = c.getBindingResult().getAllErrors();
        StringBuffer errorMsg = new StringBuffer();
        errors.stream().forEach(x -> {
            errorMsg.append(x.getDefaultMessage()).append(";");
        });
        return ApiResult.fail(ResultCodeEnum.BODY_NOT_MATCH.getCode(), errorMsg.toString());
    }


    /**
     * 表单方式参数校验
     *
     * @param cve
     * @param httpServletRequest
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ApiResult methodArgNotValidException(ConstraintViolationException cve, HttpServletRequest httpServletRequest) {
        cve.printStackTrace();

        log.error(cve.getMessage());
        Set<ConstraintViolation<?>> cves = cve.getConstraintViolations();
        StringBuffer errorMsg = new StringBuffer();
        cves.forEach(ex -> errorMsg.append(ex.getMessage()));
        return ApiResult.fail(ResultCodeEnum.BODY_NOT_MATCH.getCode(), errorMsg.toString());
    }

    /**
     * 处理空指针的异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public ApiResult exceptionHandler(HttpServletRequest req, NullPointerException e) {
       e.printStackTrace();
        log.error("发生空指针异常！原因是:" + e.toString()+e.getMessage());
        return ApiResult.fail(ResultCodeEnum.BODY_NOT_MATCH);
    }

    /**
     * 类型转换异常
     */
    @ExceptionHandler(ClassCastException.class)
    public ApiResult classCastExceptionHandler(ClassCastException e) {
        e.printStackTrace();
        log.error("类型转换异常！原因是:" + e.toString());
        StackTraceElement[] elements = e.getStackTrace();
        String message = StringUtils.EMPTY;
        if (elements.length > 0) {
            StackTraceElement element = elements[0];
            message = StringUtils.join("控制器", element.getClassName(), ".", element.getMethodName(), "类的第", element.getLineNumber(), "行发生", e.toString(), "异常");
        }
        if (StringUtils.isBlank(message)) {
            message = e.toString();
        }
        return ApiResult.fail(ResultCodeEnum.BODY_NOT_MATCH.getCode(), message);
    }


    /**
     * 自定义业务异常处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler({BusinessException.class})
    public ApiResult businessException(BusinessException e) {
        return ApiResult.fail(e.getCode(), e.getMessage());
    }


}
